﻿using System.Linq;
using System.Windows.Forms;

namespace Borg.Framework
{
    public class RegisterCheckedListBox : CheckedListBox, IAttachable
    {
        public RegisterCheckedListBox()
        {
            Enabled = false;
        }

        public void Attach(SlotInfo slot)
        {
            Slot = slot;
            
            Slot.Registered += Registered;
            Slot.Deregistered += Deregistered;
            
            Runtime.Repository.PluginAdded += PluginAdded;
            Runtime.Repository.PluginRemoved += PluginRemoved;
            
            Items.Clear();

            foreach (var plugType in Runtime.Repository.PlugTypeInfos.
                Where(plugType => plugType.Name.Equals(Slot.Name)))
                Items.Add(plugType, plugType.ExtensionTypeInfo);

            Enabled = true;
        }

        public void Deregistered(object sender, RegisterEventArgs args)
        {
            noUpdate = true;
            SetItemChecked(Items.IndexOf(args.PlugTypeInfo), false);
            noUpdate = false;
        }

        public void Detach()
        {
            Enabled = false;

            Slot.Registered -= Registered;
            Slot.Deregistered -= Deregistered;
            
            Runtime.Repository.PluginAdded -= PluginAdded;
            Runtime.Repository.PluginRemoved -= PluginRemoved;
            
            Items.Clear();
            Slot = null;
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (Slot != null)
                Detach();
        }

        protected override void OnItemCheck(ItemCheckEventArgs args)
        {
            base.OnItemCheck(args);

            if (noUpdate)
                return;

            var kvPair = Items[args.Index];
            var key = (PlugTypeInfo)kvPair.Key;

            switch (args.NewValue)
            {
                case CheckState.Unchecked:
                    key.Deregister(Slot);
                    break;

                case CheckState.Checked:
                    noUpdate = true;
                    key.Register(Slot);
                    break;
            }
        }

        public void PluginAdded(object sender, PluginEventArgs args)
        {
            foreach (var pti in
                from eti in args.ExtensionTypeInfos
                from pti in eti.PlugTypeInfos
                where pti.Name.Equals(Slot.Name)
                select pti)
                Items.Add(pti, pti.ExtensionTypeInfo);
        }

        public void PluginRemoved(object sender, PluginEventArgs args)
        {
            foreach (var pti in
                from eti in args.ExtensionTypeInfos
                from pti in eti.PlugTypeInfos
                where pti.Name.Equals(Slot.Name)
                select pti)
                Items.Remove(pti);
        }

        public void Registered(object sender, RegisterEventArgs args)
        {
            noUpdate = true;
            SetItemChecked(Items.IndexOf(args.PlugTypeInfo), true);
            noUpdate = false;
        }

        public SlotInfo Slot { get; private set; }
    }
}

